home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-07-18 | 17.8 KB | 360 lines | [TEXT/R*ch] |
- New Floater Notes 7/95:
-
- There is no change to the API, so it should mostly just be a drop-in
- replacement, but there are two possible caveats:
-
- 1) The WindowRecordExtensions structure doesn't exist any more, so if any of your
- code depends on it (it shouldn't) you'll have to change it.
-
- 2) If your application uses the window refCon you'll have to change some code:
- Any windows created with NewReferencedWindow or GetNewReferencedWindow now use
- the window refCon to store a handle to the stuff that used to be in the old
- WindowRecordExtensions structure. However, a refCon is still provided for you:
- you simply need to replace any calls to the toolbox routines GetWRefCon and
- SetWRefCon in your code with calls to GetExtWRefCon and SetExtWRefCon, which are
- provided in WindowExtensions.c.
-
- Below is a list of the bugs reported and comments about how they were resolved. Please
- send any further bugs to me at dkj@apple.com. No promises, but as long as time permits
- I'll try to maintain this code.
-
- Dave Johnson
-
- ======================================================================
- > GetNewReferencedWindow() uses the WDEF resource ID to determine whether or
- > not a window is a floater. It gets the WDEF resource ID by passing the
- > windowDefProc handle to GetResInfo(). Under 24-bit mode, the Window Manager
- > uses the high byte of the windowDefProc handle to store the WDEF variant
- > code. So if a non-zero variant is used in 24-bit mode, the Resource Manager
- > gets an invalid handle, returns -1 for the ID, and the window is treated as
- > a non-floating window. In addition to keeping the window from floating,
- > this can lead to crashes or other problems in applications that rely on the
- > windowKind field to distinguish between floaters and document windows.
- >
- > I believe the fix is to call StripAddress on the windowDefProc handle in
- > the GetWindowDefProc() function as below...
- >
- > Michael Wolfinbarger
- > Oklahoma Climatological Survey
- > wolfie@uoknor.edu
-
- Fixed: GetNewReferencedWindow now uses a different method of determining whether
- the WIND specifies a floater: it looks inside the WIND itself for the WDEF ID.
-
- ======================================================================
- > It seems that if there are open non-floating windows, and a new window A is
- > opened as invisible and with behind = -1, and a second window B is then opened
- > also as invisible with behind = -1, and then ShowReferencedWindow is called to
- > make window B visible, it never receives an activate event.
-
- I couldn't reproduce this, but I didn't try until AFTER the big rewrite, so I
- assume it was fixed along the way.
-
- ======================================================================
- > We noticed that the API does not allow one to specify the curvature of a rounded
- > window, e.g., rDocProc. That is fine, but we noticed that the rounded windows
- > that were produced by NewReferencedWindow didn't look all that "rounded" as we
- > expected. A little exploration into the code reveals why. The constant
- > noGrowDocProc was being erroneously added to rDocProc to produce a variant of
- > rDocProc+4, whereas the "standard" curvature of a window is rDocProc+0 or
- > rDocProc+5. The noGrowDocProc constant doesn't apply to the rounded window type,
- > and it seems unnatural to affect the curvature of the titlebar when the
- > kHasGrowBoxMask flag is changed.
- >
- > The change to the code is simple; from
- >
- > if (!(attributes & kHasGrowBoxMask))
- >
- > to
- >
- > if (titleBarType != kHasRoundedTitlebarMask && !(attributes & kHasGrowBoxMask))
- >
- > does the trick, and makes the windows look nice and rounded like we'd expect.
-
- Fixed. Also note that the process of turning window attributes (defined in
- WindowExtensions.h) into procIDs and state booleans was broken out into a new
- routine, AttributesToWindowInfo. This simplified NewWindowReference a lot.
-
- ======================================================================
- > The routine HideReferencedWindow does not behave properly if you attempt to hide
- > more than one window at a time. The result of hiding two windows is to leave the
- > windowing environment in a confused state: hiding the second window can make the
- > code think that the first hidden window is the frontmost nonfloater, even if
- > there are visible nonfloaters. If you are interested, we will be happy to
- > forward a revised version of the routine to you, which corrects this problem.
- > Our correction unfortunately requires more than just a line or two of code.
-
- I couldn't reproduce this, but I didn't try until AFTER the big rewrite, so I
- assume it was fixed along the way.
-
- ======================================================================
- > The routines SuspendFloatingWindows and ResumeFloatingWindows do not behave as we
- > would expect. The sample application you provide simply calls
- > SuspendFloatingWindows when the application receives a suspend event. But if
- > there are no floating windows open, first visible document window never receives
- > a deactivate event. If there are floating windows open, the window does receive
- > a deactivate event. The same is true for a resume event.
- >
- > The obvious solution is for SuspendFloatingWindows never to deactivate the first
- > visible document window, or always to deactivate the first visible document
- > window, but not to deactivate it only sometimes. We have changed the code so
- > that SuspendFloatingWindows always deactivates the first visible document window,
- > and so that ResumeFloatingWindows always activates the first visible document
- > window, since there is no sense in making the event handler do extra work. The
- > necessary change is trivial.
-
- Fixed. The first doc window is always activated or deactivated. If the first
- visible window is modal, nothing is done, preserving the state of the floaters
- and first doc window.
-
- ======================================================================
-
- > As long as I have you here, I might also make a suggestion. I was surprised to
- > see the call to SelectWindow in the SelectReferencedWindow routine; this seems to
- > be the only place where the main event loop is relied upon to activate a window.
- > Note that the result of this is that the application will behave differently
- > depending on whether or not floating windows are open: if floating windows are
- > open, the window will be activated immediately; if no floating windows are open,
- > the window will not be activated until we return to the main event loop. In our
- > application, this was undesirable, so we changed the code to:
- >
- > if (lastFloatingWindow == nil)
- > {
- > DeactivateWindow(currentFrontWindow);
- > BringToFront((WindowPtr) windowToSelect);
- > HiliteWindow((WindowPtr)windowToSelect, kActivateWindow);
- > ActivateWindow(windowToSelect);
- > } else {
-
- Fixed.
-
- ==============================================
- > When compiling with the -d STRICT_WINDOWS compiler flag, the WindowRecord
- > structure is no longer defined. As I understand things, this is to move toward a
- > fully preemptive Toolbox by making opaque toolbox interface objects.
- >
- > As you know, when Copland arrives it may no longer be true that WindowRef ==
- > WindowPtr. In fact, a WindowRef, if used as a pointer, will probably point to
- > somewhere around Neptune.
- >
- > If this is the case, then it is not a good thing to encapsulate a WindowRecord
- > inside your WindowRecordExtensions structure, and it is certainly bad to typecast
- > a WindowRef (like you might get back from the FrontWindow call) to a
- > WindowRecordExtensions record.
- >
- > I had this same problem last year, when I first heard that our old friend the
- > WindowPtr was going away. So I decided to create my own window objects and store
- > them in a global table. That way I could still access my window data and keep my
- > code removed from any toolbox dependencies.
-
- Fixed. After long and arduous debate, I decided to use the refCon of the window,
- rather than build and manage my own list. It was less work, and seemed like it
- would have the least impact on the existing API. I did, however, provide a
- replacement refCon that anyone can use. Users simply need to change all existing
- Get/SetWRefCon calls to Get/SetExtWRefCon: these are accessor routines that I
- wrote to use the new refCon. Pretty lightweight that way...
-
- ======================================================================
- > I looked over the latest "develop 18" code that Troy sent me and noticed that the
- > new routine ValidateWindowList() doesn't make use of the WindowIsModal function.
- > I suppose it would require an odd set of circumstances for ValidateWindowList to
- > be called while a modal window was in existence, but I bet it will happen to
- > someone sometime.
-
- Fixed, ValidateWindowList just returns if the front window is modal.
- ======================================================================
- > Another thing that would be nice is if DeactivateFloatersAndFirstDocumentWindow()
- > and ActivateFloatersAndFirstDocumentWindow() behaved like ShowPen() and
- > HidePen(), and incremented a "activate level". Although I've always thought it
- > was poor interface design to do so, some programs display dialogs on top of each
- > other. If they have a standard routine that display dialogs then
- > ActivateFloatersAndFirstDocumentWindow() could end up getting called
- > inappropriately when the top dialog is dismissed. A level count would prevent
- > this and simplify the model.
-
- Fixed, I didn't use a level count, but
- ActivateFloatersAndFirstDocumentWindow checks for a modal dialog, and
- if one's up it does nothing.
- ======================================================================
- > It has severe problems with invisible windows. If you have invisible windows
- > around, it is possible for the code to orphan a window from the process'
- > window list, with rather disasterous results.
- >
- > Basically, wherever the code uses the variable "windowBehind", it's broken.
- > The reordering of the window list that goes on there can cause windows to be
- > orphaned. I glanced at the new version from Dean that Troy Gaul sent me
- > today and it appears to still have this problem.
- >
- > Here are the relevant modifications I have made. They seem to work, but have
- > not been heavily tested. They are, however, definitely an improvement over
- > the original w.r.t. my usage of the floating windows code.
-
- << code deleted >>
- Fixed, more or less, I think :-). ShowReferencedWindow and HideReferencedWindow
- were rewritten, pretty much from the ground up, and (I think) are much better. I
- expect some bugs will be found, though...
-
- ======================================================================
-
- > 1. We found it necessary to add code to NewWindowReference to support windows of
- > type movableDBoxProc.
- >
- > 2. We added a constant kHasVerticalTitlebarMask and appropriate code to
- > NewWindowReference to support Infinity Windoid 3.0's vertical titlebar feature.
- >
- > 3. We added code to NewWindowReference to support Infinity Windoid 3.0's zoom and
- > grow box features.
-
- Fixed, all the variation codes and such match the 7.5 values (and Infinity 3.0),
- and movable modals are created correctly.
-
- ================================================================================
-
- > There is an implementation nasty bug in the Floater Sample.
- >
- > You can reveal it by:
- > - closing both floating windows,
- > - opening the Find Dialog and moving it over the rectangle inside the
- > 'Untitled' window (if not already here),
- > - closing the Find Dialog.
- > Then the rectangle is redrawn empty as of an inactive window although the window is
- > active.
- >
- > That is due to the doFill checking in DrawWindowContent():
- > - 'true' is compiled by CW as 0x01,
- > - while doFill is 0xFF when TRUE (hilite flag),
- > so doFill can be seen as FALSE!
- >
- > IMHO, the '== true' comparison is generally a risky business. The lazy people,
- > like me, who prefers to type only "if (doFill)" cannot run into this kind of
- > implementation problem.
-
- Fixed! Thanks! That's a bizarre one. I actually think of this as a compiler bug myself,
- but that's probably unfair of me. :-)
-
- ======================================================================
- After first test of rewrite:
- ======================================================================
- > 1. I am using SC 8.0.1 with Universal Interfaces 2.0 in “MPW Latest”
- > on ETO #17. I encountered three compiler errors:
- >
- > i. Since GetWasVisible returns a Boolean, I needed to change return
- > nil to return FALSE.
- >
- > ii. Since GetExtWRefCon returns a long, I needed to change return nil
- > to return 0.
- >
- > iii. I needed to #include <Errors.h> to define resNotFound, used in
- > GetWINDStats.
-
- Fixed.
- ======================================================================
- > 2. For consistency, I suggest that you make GetNextVisibleWindow an
- > "extern pascal" like all the other routines in the .h file.
-
- Fixed
- ======================================================================
- > 3. I was somewhat surprised when I read "Who ever calls NewWindow to
- > make a dialog anyway?", since we rely on common a window creation
- > scheme for all our windowing needs. The current implementation of
- > CheckWindowOrdering will place a modal window (including movable
- > modal dialogs) behind all floaters, which is not the desired result.
- >
- > Are you recommending that we call NewDialog instead of NewWindow to
- > create our dialogs, and make sure we use Dialog Manager calls
- > everywhere so that we comply with STRICT_WINDOWS? We were faithfully
- > following the advice in Technical #203, Managerial Abuse, and using
- > the window manager instead of the dialog manager for our complex
- > modal windows. Is the best option for us to hack CheckWindowOrdering
- > to place modals in front of everything? Since modal windows are not
- > supported correctly, shouldn't you remove them from
- > AttributesToWindowInfo?
-
- Yikes. It was a little cavalier of me to eliminate the modal dialog
- case, and it's fixed now (both NewWindowReference and
- GetNewWindowReference check for modal windows, CheckWindowOdering
- only allows modals to be created in front of all windows, etc.)
- HOWEVER: my recommendation is definitely to make your code compile
- with STRICT_WINDOWS (srict EVERYTHING, actually). Someday, you'll
- have no choice, as a matter of fact, so the sooner the better. If
- that means you have to abuse the Dialog manager a bit, so be it (the
- dialog manager is a little more robust than when that tech note was
- written). If you can do it without dialog manager calls, that's even
- better.
- ======================================================================
- > 4. NewWindowReference currently ingores the refCon that is passed to
- > it as an argument. This causes our application to crash, since our
- > activate routine, (which is called immediately by NewWindowReference)
- > needs the refCon. Our activate routine calls GetExtWRefCon, which
- > returns a random result since the userRefCon field is never
- > initialized.
-
- Whoops, sorry. Fixed. Also, GetNewWindowReference preserves whatever
- refcon was specified in the WIND resource.
-
- ===========================================================================
- > two more suggestions on your new floating windows library.
- >
- > 1. GetWindowPortRect() isn't used in your library. Also, it clashes
- > with ZoomCode.c
- >
- > 2. Why are GetWasVisible()/SetWasVisible() public?
- > Can an application responsibly use this?
-
- Fixed: Removed GetWindowPortRect. "Privatized" Get/SetWasVisible.
-
- ===========================================================================
- > I had three problems:
- >
- > 1. NewWindowReference ignores the refCon passed to it.
- >
- > 2. SetWRefCon is used in Utilities.c This was a mall change but this
- > is going to happen: legacy or snarfed code will need to be changed.
- >
- > 3. I don't know if this is my fault, but you use Get1Resource to get
- > the appropriate WIND resource. I changed this to GetResource. I
- > can't understand why it shouldn't be GetResource.
- >
- > I did a little more checking with my application.
- > Get1Resource('WIND', ..) was failing. There are two resource files,
- > the application resource fork and the preferences file. I use
- > StdPrefsLib.c to manage the preferences file.
-
- 1. Fixed.
-
- 2. Yep, it's bound to happen, unfortunately. Anyone using this code
- should do a very complete search for Get/SetWRefCon and change ALL
- occurrences.
-
- 3. I'm going to leave it Get1Resource, since the app's resource file
- should be topmost in the resource chain when GetNewWindowReference is
- called. (That is, unless I hear from other folks about this too.)
- StdPrefsLib.c is probably at fault, not restoring the resource chain
- after its operations.
-
- =========================================================================
- > A problem occurs whenever we create a modal window. Our standard
- > method is to create a window as invisible, call NewControl, LNew,
- > etc., and then call ShowReferencedWindow. The problem is that
- > ShowReferencedWindow doesn't make the window the FrontWindow if there
- > are floating windows open. Thus, no matter what kind of filtering we
- > do in the event loop, the user can always click on the desktop to
- > switch out of the app, because the system does not see the FrontWindow
- > as modal.
- >
- > A call to BringToFront if the window is modal (either in
- > ShowReferencedWindow or in our calling code) should do the trick.
-
- Fixed. This necessitated another change, too: WindowIsModal used to
- return true only if the window's kind was dialogKind, but these
- manually created modal windows don't qualify. I tried just setting
- the window's kind to dialogKind myself, but that's disastrous (the
- system makes assumptions about such windows, and calls all kinds of
- dialog routines behind your back, resulting in nasty crashes). I
- tried changing WindowIsModal to return true if the window was
- dialogKind OR if its variant was a modal type (it used to be AND) but
- it turns out that some floater variants overlap with regular variants
- (for instance, a floater with a zoom box returns variant 5, the same
- as a movable modal). Now, WindowIsModal returns true if the window is
- NOT a floater, AND it is either dialogKind or a modal variant. Whew!
-